package com.example.socket.server;

import com.example.socket.filter.FilterHandler;
import com.example.socket.filter.session.SessionManager;
import com.example.socket.handler.NettyHandler;
import com.example.socket.thread.NamedThreadFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * @author frank
 * 主类
 */
public class GameServer implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(GameServer.class);
    private ApplicationContext applicationContext;
    private NettyHandler handler;
    private List<FilterHandler> filters = new ArrayList<>();
    private Channel channel;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workGroupl;

    @PostConstruct
    public void initializer() {
        filters = new ArrayList<>(applicationContext.getBeansOfType(FilterHandler.class).values());
        Collections.sort(filters, (o1, o2) -> o1.getOrder() - o2.getOrder());
        bossGroup = new NioEventLoopGroup(1, new NamedThreadFactory("服务器BOSS线程"));
    }

    public void start(ServerConfig config, EventLoopGroup workerGroup,
                      ExecutorService executor, SessionManager sessionManager) {
        this.workGroupl = workerGroup;
        try {
            ServerBootstrap connector = new ServerBootstrap();
            connector.group(bossGroup, workerGroup);
            connector.channel(NioServerSocketChannel.class);
            //设置hanlder
            connector.childHandler(new ServerHandlerInitializer(handler, executor, sessionManager, filters));
            //设置socket参数
            config.getSessionConfig().buildTcpServerOption(connector);
            //绑定端口
            InetSocketAddress address = config.getAddress();
            connector.localAddress(address);
            ChannelFuture bind = connector.bind();
            channel = bind.sync().channel();
            if (logger.isInfoEnabled()) {
                logger.info("绑定服务地址和端口到[{}:{}]", address.getHostName(), address.getPort());
            }
        } catch (InterruptedException e) {
            logger.error("启动异常终止", e);
        }
    }

    public void destroy() {
        if (channel != null) {
            logger.error("关闭服务器端口:{}", channel.localAddress());
            channel.close().awaitUninterruptibly();
        }
        workGroupl.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    public void setHandler(NettyHandler handler) {
        this.handler = handler;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
